package com;


import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class test {
    private static Logger logger= LoggerFactory.getLogger(test.class);
    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
    public static final String CHATSET = "utf-8";

    //公钥A、私钥A
    public static String publicKey_A = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMiuFv0apKaSRvnSCJwqv1VvQ3EpwcDS1sP6ElxsMmimDbD7zgOzTffMD5ZB2dbocI+SjzZdNF62E7wUrqGncU0CAwEAAQ==";
    public static String privateKey_A = "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAyK4W/RqkppJG+dIInCq/VW9DcSnBwNLWw/oSXGwyaKYNsPvOA7NN98wPlkHZ1uhwj5KPNl00XrYTvBSuoadxTQIDAQABAkEAhEBmmgrS84t3BvBqCDELwwv+UDeKnr7UFndZXltXpSqO3xmgxmYHeCBtVbkY+J7bHtBzT2r5akzSrdoCtc8X6QIhAOwsbnt5UBJ4X9Ep3EBRSXSPVfNr8oF8uPabfYO8rB6TAiEA2YbfYXQYodlyfpFYV5afHcbQzVf7kZ+Bua/cbj3SPJ8CIQCMS1yaJpdlUXKB2t8GqgL7pcYGIyLcvs1VWUq3PhX01wIgDCebJ8ji73hFC4l3lD1YWsOXO0IlTnfJOeT3vjk6HCUCIQDSVDAXgAXymHEuFmejc+fAuN+QsZtx";

    //公钥B、私钥B
    public static String publicKey_B = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+AKHvKfbRd+69wcmtdq+/Ngz24crtc792nxH/oZBOo8lvp/vMs4CmKutGOpG7s9q7/BWiK41oeU+AuV7VaHycCAwEAAQ==";
    public static String privateKey_B = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAv4Aoe8p9tF37r3Bya12r782DPbhyu1zv3afEf+hkE6jyW+n+8yzgKYq60Y6kbuz2rv8FaIrjWh5T4C5XtVofJwIDAQABAkAXzkO6F9MGoARQq+bdZ/iex+p/urUwi34aDOgFioseUlP12Zin4IRZkc1BA6DMmrd4JzCO50vSmhzrxiJSqkpBAiEA9ETiK2scNx1zhdukXOrtRoTP9cLfblCH8vw0SIgNQEcCIQDIsoYI92vff/jz08s9W9scIw/F9UyZ1iaPdl99CWV6IQIgUhV/x0VkIuVDt9y6W/saJxNkatrEiGaJeM7lpuYJResCIHj070c0JzV6YUZCnTkLxVB96SG7p0EIChFonEA1i41BAiEA5CWKPvj2E9SA3UKHQySPqd58vDytsSVm8FMIBOj+4Ag=";

    //将需要发送的消息封装在Map中
    public static Map<String, String> communicationParams = null;

    public static void main(String[] args) {
        //记录debug级别的信息
        logger.debug("debug MESSAGE");
        //记录info级别的信息
        logger.info("info MESSAGE");
        //记录error级别的信息
        logger.error("error MESSAGE");
        test s = new test();
        // A给B发消息
        s.ASendMsgToB();

        // B接收来自A的消息
        s.BReceiverFromA();
    }
    private static void ASendMsgToB() {
        //消息明文
        String msg = "你好";

        //加密
        String encryptMsg = encyptByPublickey(msg, publicKey_B);

        //签名
        String sign = signByPrivateKey(encryptMsg, privateKey_A);
        //发送消息
        communicationParams = new HashMap<String, String>();
        communicationParams.put("encryptMsg", encryptMsg);
        communicationParams.put("sign", sign);
        logger.info("A发送给B的消息", JSON.toJSONString(communicationParams));
        logger.info("_______________________________");
    }

    private static void BReceiverFromA() {
        //接受消息
        Map<String, String> receiveMsg = communicationParams;
        logger.info("B接收到A的消息", JSON.toJSONString(receiveMsg));
        String sign = receiveMsg.get("sign");
        String encryptMsg = receiveMsg.get("encryptMsg");
        //验签
        Boolean tf = verifySignPublickey(encryptMsg, publicKey_A, sign);
        if (tf) {
            logger.info("验签通过，说明这个信息是B认可的用户发送过来的");
        }
        //解密
        String msg = decryptByPrivateKey(encryptMsg, privateKey_B);
        logger.info("解密成功，说明这个信息就是发送给B的");
        logger.info("B收到的消息{}", msg);
    }

    /**
     * RSA公钥加密
     * str加密字符串
     * publicKey公钥
     * return密文
     */
    private static String encyptByPublickey(String str, String publicKey) {
        try {
            //base64编码的公钥
            byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(publicKey);
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));

            //RSA加密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            String outStr = org.apache.commons.codec.binary.Base64.encodeBase64String(cipher.doFinal(str.getBytes(CHATSET)));
            return outStr;

        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        }
        return null;
    }

    /**
     * RSA私钥解密
     * str加密字符串
     * privateKey私钥
     * return明文
     */
    private static String decryptByPrivateKey(String str, String privateKey) {
        try {
            //base64解码加密后的字符串
            byte[] inputByte = org.apache.commons.codec.binary.Base64.decodeBase64(str.getBytes(CHATSET));

            //base64编码的私钥
            byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(privateKey);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));

            //RSA解密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            String outStr = new String(cipher.doFinal(inputByte));
            return outStr;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        }
        return null;
    }

    /**
     * RSA签名检查
     * content待签名的数据
     * sign 签名值
     * publicKey公钥
     * return 布尔值
     */
    private static Boolean verifySignPublickey(String content, String publicKey, String sign) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Base64 Base64 = new Base64();
            byte[] encodedKey = Base64.decode(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(CHATSET));

            boolean bverify = signature.verify(Base64.decode(sign));
            return bverify;

        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        }
        return false;
    }

    /**
     * RSA签名
     * @param content 待签名数据
     * @param privateKey 商户私钥
     * @return 签名值
     */
    private static String signByPrivateKey(String content, String privateKey) {
        try {
            Base64 Base64 = new Base64();
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            PrivateKey priKey = keyf.generatePrivate(priPKCS8);

            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);

            signature.initSign(priKey);
            signature.update(content.getBytes(CHATSET));

            byte[] signed = signature.sign();

            return Base64.encodeAsString(signed);

        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        }
        return null;
    }
}
